package models

import (
	"fmt"
	"gitchina/kly_service/data"
	"gitchina/kly_service/util/sms"
	"math"
	"strconv"
)

type MockOrder struct {
	LoadCargoTime        string  `json:"load_cargo_time"`
	CarrierOwnerPhone    string  `json:"carrier_owner_phone"`
	CargoOwnerPhone      string  `json:"cargo_owner_phone"`
	VehicleNO            string  `json:"vehicle_no"`
	Consignee            string  `json:"consignee"`
	ConsigneePhone       string  `json:"consignee_phone"`
	StartArea            string  `json:"start_area"`
	StartLocation        string  `json:"start_location"`
	EndArea              string  `json:"end_area"`
	EndLocation          string  `json:"end_location"`
	CargoName            string  `json:"cargo_name"`
	CargoWeight          float64 `json:"cargo_weight"`
	CargoBulk            float32 `json:"cargo_bulk"`
	CargoCount           int     `json:"cargo_count"`
	CargoValue           float32 `json:"cargo_value"`
	CargoType            int     `json:"cargo_type"`
	ArrivalTime          string  `json:"arrival_time"`
	LogisticCorp         string  `json:"logistic_corp"`
	TaxRatio             float32 `json:"tax_ratio"`
	PriceIncludeTax      float32 `json:"price_include_tax"`
	BankName             string  `json:"bank_name"`
	PayeeName            string  `json:"payee_name"`
	PayeeIDCard          string  `json:"payee_card"`
	BankCard             string  `json:"bank_card"`
	InvoiceTitle         string  `json:"invoice_title"`
	InvoiceTaxNO         string  `json:"invoice_tax_no"`
	InvoiceAddr          string  `json:"invoice_addr"`
	InvoiceRecvName      string  `json:"invoice_recv_name"`
	InvoiceRecvPhone     string  `json:"invoice_recv_phone"`
	InvoiceZipCode       string  `json:"invoice_zip_code"`
	InvoiceBankOfDeposit string  `json:"invoice_bank_deposit"`
	InvoiceBankCardNO    string  `json:"invoice_bank_card_no"`
	InvoiceIssueCorp     string  `json:"invoice_issue_corp"`
	OrderTime            string  `json:"order_time"`
	Remark               string  `json:"remark"`
	InvoiceState         int     `json:"invoice_state"`
	ContractType         int     `json:"contract_type"`
	PubID                ID
	CarrierOwnerID       ID
	CargoOwnerID         ID
	WaybillID            ID
	pubid                int
	waybillid            int
	StartAreaID          int
	EndAreaID            int
	carrierownerid       int
	cargoownerid         int
	carrierOwnerType     int
	cargoOwner           Member
	waybillRQ            MakeWaybillRQ
}

func (mock *MockOrder) Mock() error {
	sms.CloseSMS = true
	defer func() {
		sms.CloseSMS = false
	}()
	err := mock.carrierPub()
	if err != nil {
		if err.Error() == "exists" {
			return nil
		} else {
			return err
		}
	}
	err = mock.makeWaybill()
	if err != nil {
		return err
	}
	err = mock.updateWaybill()
	if err != nil {
		return err
	}
	err = mock.complete()
	if err != nil {
		return err
	}
	return mock.modifyTime()
	return nil
}

func (mock *MockOrder) Delete() {
	var repo data.OrderRepo

	repo.OrderExistsThenDelete(mock.Remark)
}

func (mock *MockOrder) carrierPub() error {
	var m Member
	var l Logistics
	var id int
	var err error

	if len(mock.CarrierOwnerPhone) != 0 {
		if id, err = m.GetMemberIDByPhone(mock.CarrierOwnerPhone); err != nil {
			return err
		}
	} else {
		if id, err = m.GetMemberIDByVehicleNO(mock.VehicleNO); err != nil {
			return err
		}
	}

	mock.carrierownerid = id
	var memberRepo data.MemberRepo
	dto, err := memberRepo.GetMemberInfo(mock.carrierownerid)
	if err != nil {
		return err
	}
	mock.carrierOwnerType = dto.TypeId

	var payRepo data.PayRepo
	_, err = payRepo.GetWallet(id)
	if err != nil {
		payRepo.AddWallet(data.WalletDto{MemberId: id})
	}

	mid := new(ID)
	mid.Encode(ID_Shard, ID_Ver, ID_Member_Category, int64(id))
	mock.CarrierOwnerID = *mid
	mock.StartAreaID, _ = strconv.Atoi(l.GetAreaID(mock.StartArea))
	mock.EndAreaID, _ = strconv.Atoi(l.GetAreaID(mock.EndArea))
	if len(mock.LoadCargoTime) == 10 {
		mock.LoadCargoTime += " 00:00:00"
	}
	pid, err := l.CarrierPub(*mid, &CarrierPubRQ{
		StartArea:        l.GetAreaID(mock.StartArea),
		EndArea:          l.GetAreaID(mock.EndArea),
		ShipmentTime:     mock.LoadCargoTime,
		Load:             int(math.Round(mock.CargoWeight)),
		Price:            float32(mock.PriceIncludeTax),
		SrcLocationTitle: mock.StartArea,
		SrcLocation:      mock.StartLocation,
		DestLocation:     mock.EndArea,
	}, true)
	if err != nil {
		return err
	}
	mock.PubID = pid
	_, _, _, v, err := pid.Decode()
	mock.pubid = int(v)
	return err
}

func (mock *MockOrder) makeWaybill() error {
	var o Order
	var m Member

	cargoOwnerID := new(ID)
	id, err := m.GetMemberIDByPhone(mock.CargoOwnerPhone)
	if err != nil {
		return err
	}
	cargoOwnerID.Encode(ID_Shard, ID_Ver, ID_Member_Category, int64(id))
	cargoOwner, err := m.GetMemberInfo(*cargoOwnerID)
	if err != nil {
		return err
	}
	mock.CargoOwnerID = *cargoOwnerID

	var repo data.PayRepo
	_, err = repo.GetWallet(id)
	if err != nil {
		repo.AddWallet(data.WalletDto{MemberId: id})
	}

	rq := &MakeWaybillRQ{
		StartArea:         mock.StartAreaID,
		StartAddr:         mock.StartLocation,
		EndArea:           mock.EndAreaID,
		EndAddr:           mock.EndLocation,
		SrcLocationTitle:  mock.StartArea,
		DestLocationTitle: mock.EndArea,
		SrcLocation:       mock.StartArea,
		DestLocation:      mock.EndArea,
		ShipmentTime:      mock.LoadCargoTime,
		CarrierOwnerId:    mock.carrierownerid,
		CarrierPubId:      mock.PubID,
		CargoName:         mock.CargoName,
		CargoType:         mock.CargoType,
		CargoBulk:         mock.CargoBulk,
		CargoWeight:       float32(mock.CargoWeight),
		CargoCount:        mock.CargoCount,
		CargoValue:        mock.CargoValue,
		ArrivalTime:       mock.ArrivalTime,
		Deposit:           0,
		Consignor:         cargoOwner.Name,
		Consignee:         mock.Consignee,
		ConsigneePhone:    mock.ConsigneePhone,
		NeedInvoice:       true,
		NeedInsurance:     false,
		NeedOilCard:       false,
		PaymentTerm:       1,
		State:             2,
		ContractType:      mock.ContractType,
		TaxRatio:          mock.TaxRatio,
		PriceIncludeTax:   mock.PriceIncludeTax,
		Remark:            mock.Remark,
	}

	//if mock.carrierOwnerType == 4 {
	//	//rq.Price = float32(mock.PriceIncludeTax * 0.922)
	//	rq.Price = float32(mock.PriceIncludeTax * 0.93)
	//} else {
	//	rq.Price = float32(mock.PriceIncludeTax * 0.93)
	//}

	if mock.TaxRatio == 0 {
		mock.TaxRatio = 0.93
	}

	rq.Price = float32(mock.PriceIncludeTax * mock.TaxRatio)

	mock.waybillRQ = *rq
	r, err := o.MakeWaybill(*cargoOwnerID, rq)
	if err != nil {
		return err
	}
	mock.WaybillID = r.WaybillId
	_, _, _, v, err := mock.WaybillID.Decode()
	mock.waybillid = int(v)
	return err
}

func (mock *MockOrder) updateWaybill() error {
	var o Order
	err := o.UpdateWaybillState(mock.CarrierOwnerID, &UpdateWaybillStateWithParamsRQ{
		Id:    mock.WaybillID,
		State: 2,
	})
	if err != nil {
		return err
	}
	err = o.UpdateOfflineState(mock.CargoOwnerID, &UpdateOfflineWaybillStateWithParamsRQ{
		Id:               mock.WaybillID,
		UpdateParam:      mock.waybillRQ,
		BankName:         mock.BankName,
		PayeeName:        mock.PayeeName,
		BankCard:         mock.BankCard,
		PayeeIDCard:      mock.PayeeIDCard,
		InvoiceIssueCorp: mock.InvoiceIssueCorp,
		NeedInsurance:    false,
		ContractType:     mock.ContractType,
		InvoiceInfo: InvoicePostAddr{
			Title:         mock.InvoiceTitle,
			Addr:          mock.InvoiceAddr,
			TaxNo:         mock.InvoiceTaxNO,
			RecvName:      mock.InvoiceRecvName,
			RecvPhone:     mock.InvoiceRecvPhone,
			ZipCode:       mock.InvoiceZipCode,
			BankOfDeposit: mock.InvoiceBankOfDeposit,
			BankCardNo:    mock.InvoiceBankCardNO,
		},
	})
	err = data.SqlExec(fmt.Sprintf("UPDATE o_waybill set create_time='%s', update_time='%s' WHERE id = %d",
		mock.OrderTime, mock.OrderTime, mock.waybillid))
	if err != nil {
		return err
	}
	return err
}

func (mock *MockOrder) complete() error {
	var o Order
	err := o.UpdateWaybillState(mock.CarrierOwnerID, &UpdateWaybillStateWithParamsRQ{
		UpdateParam: MakeWaybillRQ{LogisticCorp: mock.LogisticCorp, ContractType: mock.ContractType, TaxRatio: mock.TaxRatio, PriceIncludeTax: mock.PriceIncludeTax},
		Id:          mock.WaybillID,
		State:       5,
	})
	if err != nil {
		return err
	}
	err = o.UpdateWaybillState(mock.CarrierOwnerID, &UpdateWaybillStateWithParamsRQ{
		Id:    mock.WaybillID,
		State: 6,
	})
	if err != nil {
		return err
	}
	err = o.UpdateWaybillState(mock.CargoOwnerID, &UpdateWaybillStateWithParamsRQ{
		Id:    mock.WaybillID,
		State: 7,
	})
	err = data.SqlExec(fmt.Sprintf("UPDATE o_invoice set state = %d WHERE waybill_id = %d", mock.InvoiceState, mock.waybillid))
	return err
}

func (mock *MockOrder) modifyTime() error {
	err := data.SqlExec(fmt.Sprintf("UPDATE l_carrier_pub set create_time='%s', update_time='%s' WHERE id = %d",
		mock.LoadCargoTime, mock.LoadCargoTime, mock.pubid))
	if err != nil {
		return err
	}
	err = data.SqlExec(fmt.Sprintf("UPDATE o_waybill set create_time='%s', update_time='%s' WHERE id = %d",
		mock.OrderTime, mock.OrderTime, mock.waybillid))
	if err != nil {
		return err
	}
	err = data.SqlExec(fmt.Sprintf("UPDATE o_invoice set create_time='%s', update_time='%s', apply_time='%s' WHERE waybill_id = %d",
		mock.OrderTime, mock.OrderTime, mock.OrderTime, mock.waybillid))
	if err != nil {
		return err
	}
	err = data.SqlExec(fmt.Sprintf("UPDATE t_pay_offline set create_time='%s'WHERE waybill_id = %d", mock.OrderTime, mock.waybillid))
	if err != nil {
		return err
	}
	err = data.SqlExec(fmt.Sprintf("UPDATE o_waybill_message set create_time='%s' WHERE waybill_id = %d", mock.OrderTime, mock.waybillid))
	if err != nil {
		return err
	}
	err = data.SqlExec(fmt.Sprintf("UPDATE o_waybill_score set create_time='%s' WHERE waybill_id = %d", mock.OrderTime, mock.waybillid))
	if err != nil {
		return err
	}
	return data.SqlExec(fmt.Sprintf("UPDATE o_contract set create_time='%s', update_time='%s' WHERE waybill_id = %d",
		mock.OrderTime, mock.OrderTime, mock.waybillid))
}
